/*-
 * $Id: Border.java 4 2010-11-04 07:39:56Z andrewbass $
 */

package com.google.code.getwrong.terminalui;

/**
 * @author Andrew ``Bass'' Shcheglov (andrewbass@gmail.com)
 * @author $Author: andrewbass $
 * @version $Revision: 4 $, $Date:: 2010-11-04 07:39:56 +0000 #$
 */
public final class Border implements Component {
	private static final char C_SINGLE_HORIZONTAL = '\u2500';

	private static final char C_DOUBLE_HORIZONTAL = '\u2550';


	private static final char C_SINGLE_VERTICAL = '\u2502';

	private static final char C_DOUBLE_VERTICAL = '\u2551';


	private static final char C_SINGLE_DOWN_AND_SINGLE_RIGHT = '\u250C';

	private static final char C_SINGLE_DOWN_AND_DOUBLE_RIGHT = '\u2552';

	private static final char C_DOUBLE_DOWN_AND_SINGLE_RIGHT = '\u2553';

	private static final char C_DOUBLE_DOWN_AND_DOUBLE_RIGHT = '\u2554';


	private static final char C_SINGLE_DOWN_AND_SINGLE_LEFT = '\u2510';

	private static final char C_SINGLE_DOWN_AND_DOUBLE_LEFT = '\u2555';

	private static final char C_DOUBLE_DOWN_AND_SINGLE_LEFT = '\u2556';

	private static final char C_DOUBLE_DOWN_AND_DOUBLE_LEFT = '\u2557';


	private static final char C_SINGLE_UP_AND_SINGLE_RIGHT = '\u2514';

	private static final char C_SINGLE_UP_AND_DOUBLE_RIGHT = '\u2558';

	private static final char C_DOUBLE_UP_AND_SINGLE_RIGHT = '\u2559';

	private static final char C_DOUBLE_UP_AND_DOUBLE_RIGHT = '\u255A';


	private static final char C_SINGLE_UP_AND_SINGLE_LEFT = '\u2518';

	private static final char C_SINGLE_UP_AND_DOUBLE_LEFT = '\u255B';

	private static final char C_DOUBLE_UP_AND_SINGLE_LEFT = '\u255C';

	private static final char C_DOUBLE_UP_AND_DOUBLE_LEFT = '\u255D';


	private final Terminal terminal;

	private final Rectangle bounds;

	private final BorderStyle style;

	private final Color foreground;

	private final Color background;

	/**
	 * May be nullable.
	 */
	private final String title;


	/**
	 * @param terminal
	 * @param bounds
	 * @param style
	 * @param foreground
	 * @param background
	 * @param title
	 */
	public Border(final Terminal terminal,
			final Rectangle bounds,
			final BorderStyle style,
			final Color foreground,
			final Color background,
			final String title) {
		this.terminal = terminal;
		this.bounds = bounds;
		this.style = style;
		this.foreground = foreground;
		this.background = background;
		this.title = title;
	}


	/**
	 * @param terminal
	 * @param bounds
	 * @param style
	 * @param foreground
	 * @param background
	 */
	public Border(final Terminal terminal,
			final Rectangle bounds,
			final BorderStyle style,
			final Color foreground,
			final Color background) {
		this(terminal, bounds, style, foreground, background, null);
	}

	private char getHorizontal() {
		final boolean supportsPseudoGraphics = this.terminal.supportsPseudoGraphics();

		switch (this.style.getHorizontalStyle()) {
		case SINGLE:
			return supportsPseudoGraphics ? C_SINGLE_HORIZONTAL : '-';
		case DOUBLE:
		default:
			return supportsPseudoGraphics ? C_DOUBLE_HORIZONTAL : '=';
		}
	}

	private char getVertical() {
		if (!this.terminal.supportsPseudoGraphics()) {
			return '|';
		}

		switch (this.style.getVerticalStyle()) {
		case SINGLE:
			return C_SINGLE_VERTICAL;
		case DOUBLE:
		default:
			return C_DOUBLE_VERTICAL;
		}
	}

	private char getTopLeft() {
		if (!this.terminal.supportsPseudoGraphics()) {
			return '+';
		}

		switch (this.style.getVerticalStyle()) {
		case SINGLE:
			switch (this.style.getHorizontalStyle()) {
			case SINGLE:
				return C_SINGLE_DOWN_AND_SINGLE_RIGHT;
			case DOUBLE:
			default:
				return C_SINGLE_DOWN_AND_DOUBLE_RIGHT;
			}
		case DOUBLE:
		default:
			switch (this.style.getHorizontalStyle()) {
			case SINGLE:
				return C_DOUBLE_DOWN_AND_SINGLE_RIGHT;
			case DOUBLE:
			default:
				return C_DOUBLE_DOWN_AND_DOUBLE_RIGHT;
			}
		}
	}

	private char getTopRight() {
		if (!this.terminal.supportsPseudoGraphics()) {
			return '+';
		}

		switch (this.style.getVerticalStyle()) {
		case SINGLE:
			switch (this.style.getHorizontalStyle()) {
			case SINGLE:
				return C_SINGLE_DOWN_AND_SINGLE_LEFT;
			case DOUBLE:
			default:
				return C_SINGLE_DOWN_AND_DOUBLE_LEFT;
			}
		case DOUBLE:
		default:
			switch (this.style.getHorizontalStyle()) {
			case SINGLE:
				return C_DOUBLE_DOWN_AND_SINGLE_LEFT;
			case DOUBLE:
			default:
				return C_DOUBLE_DOWN_AND_DOUBLE_LEFT;
			}
		}
	}

	private char getBottomLeft() {
		if (!this.terminal.supportsPseudoGraphics()) {
			return '+';
		}

		switch (this.style.getVerticalStyle()) {
		case SINGLE:
			switch (this.style.getHorizontalStyle()) {
			case SINGLE:
				return C_SINGLE_UP_AND_SINGLE_RIGHT;
			case DOUBLE:
			default:
				return C_SINGLE_UP_AND_DOUBLE_RIGHT;
			}
		case DOUBLE:
		default:
			switch (this.style.getHorizontalStyle()) {
			case SINGLE:
				return C_DOUBLE_UP_AND_SINGLE_RIGHT;
			case DOUBLE:
			default:
				return C_DOUBLE_UP_AND_DOUBLE_RIGHT;
			}
		}
	}

	private char getBottomRight() {
		if (!this.terminal.supportsPseudoGraphics()) {
			return '+';
		}

		switch (this.style.getVerticalStyle()) {
		case SINGLE:
			switch (this.style.getHorizontalStyle()) {
			case SINGLE:
				return C_SINGLE_UP_AND_SINGLE_LEFT;
			case DOUBLE:
			default:
				return C_SINGLE_UP_AND_DOUBLE_LEFT;
			}
		case DOUBLE:
		default:
			switch (this.style.getHorizontalStyle()) {
			case SINGLE:
				return C_DOUBLE_UP_AND_SINGLE_LEFT;
			case DOUBLE:
			default:
				return C_DOUBLE_UP_AND_DOUBLE_LEFT;
			}
		}
	}

	/**
	 * @see Component#paint()
	 */
	@Override
	public void paint() {
		this.terminal.setForeground(this.foreground);
		this.terminal.setBackground(this.background);

		final Point origin = this.bounds.getOrigin();
		final int originX = origin.getX();
		final int originY = origin.getY();

		final Dimension dimension = this.bounds.getDimension();
		final int width = dimension.getWidth();
		final int height = dimension.getHeight();

		this.terminal.moveTo(originX, originY);
		this.terminal.print(this.getTopLeft());
		this.terminal.moveTo(originX + width - 1, originY);
		this.terminal.print(this.getTopRight());
		this.terminal.moveTo(originX, originY + height - 1);
		this.terminal.print(this.getBottomLeft());
		this.terminal.moveTo(originX + width - 1, originY + height - 1);
		this.terminal.print(this.getBottomRight());

		final char cHorizontal = getHorizontal();
		for (int i = 1; i < width - 1; i++) {
			this.terminal.moveTo(originX + i, originY);
			this.terminal.print(cHorizontal);
			this.terminal.moveTo(originX + i, originY + height - 1);
			this.terminal.print(cHorizontal);
		}

		final char cVertical = getVertical();
		for (int i = 1; i < height - 1; i++) {
			this.terminal.moveTo(originX, originY + i);
			this.terminal.print(cVertical);
			this.terminal.moveTo(originX + width - 1, originY + i);
			this.terminal.print(cVertical);
		}

		this.terminal.flush();
	}
}
